package my.shadowsocks.client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.socks.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author fengbo
 * @date 2018/10/8
 */
public class SocksServerHandler extends SimpleChannelInboundHandler<SocksRequest> {

    private static final Logger log = LoggerFactory.getLogger(SocksServerHandler.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, SocksRequest request) {
        switch (request.requestType()) {
            case INIT:
                log.info("local server init");
                ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
                ctx.write(new SocksInitResponse(SocksAuthScheme.NO_AUTH));
                break;
            case AUTH:
                log.info("local server auth");
                ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
                ctx.write(new SocksAuthResponse(SocksAuthStatus.SUCCESS));
                break;
            case CMD:
                SocksCmdRequest req = (SocksCmdRequest) request;
                if (req.cmdType() == SocksCmdType.CONNECT) {
                    log.info("local server connect");
                    ctx.pipeline().addLast(new SocksServerConnectHandler());
                    ctx.pipeline().remove(this);
                    ctx.fireChannelRead(request);
                    break;
                }
            case UNKNOWN:
            default:
                ctx.close();
                break;
        }
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        log.info("SocksServerHandler read complete!");
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
        log.error("SocksServerHandler throw error!", throwable);
        SocksServerUtils.closeOnFlush(ctx.channel());
    }
}
